package com.spzx.product.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.product.api.domain.SkuStock;
import com.spzx.product.api.domain.dto.OrderStockDTO;
import com.spzx.product.mapper.SkuStockMapper;
import com.spzx.product.service.SkuStockService;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class SkuStockServiceImpl extends ServiceImpl<SkuStockMapper , SkuStock>
        implements SkuStockService {
    @Resource
    RedisTemplate redisTemplate;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<OrderStockDTO> checkAndLockStock(List<OrderStockDTO> orderStockDTOS) {
        if(CollectionUtils.isEmpty(orderStockDTOS)){
            return null;
        }
        /*
            遍历每个orderStockDTO对象
                对每个sku的库存进行校验，如果校验成功 锁定库存
                #  1、availableNum设置无符号约束：不能为负数
                2、使用一个sql验库存锁库存
                    update sku_stock  availableNum = availableNum - skuNum , lock_num = lock_num + skuNum
                    where sku_id = 1 and (availableNum - skuNum)>=0
               3、同一组操作 要么一起成功 要么一起失败:
                    3.1 使用事务注解，抛出异常 自动回滚
                    3.2 不抛出异常，如果有更新库存失败的，恢复之前锁定的库存

         */
        //1、检查并锁定库存
        // mysql存在提交更新 提交覆盖问题
        checkLockStock(orderStockDTOS);
        //2、检查：如果有库存不足的，应该将所有锁定的库存释放掉(用户提交订单业务失败)
        //获取锁库存成功的数据集合
        List<OrderStockDTO> lockedStockDTOs = orderStockDTOS.stream().filter(orderStockDTO -> orderStockDTO.getFlag())
                .collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(lockedStockDTOs) &&  lockedStockDTOs.size() < orderStockDTOS.size()){
            //如果有锁定库存失败的数据，需要释放锁定的库存
            releaseLockStock(lockedStockDTOs);
        }
        //所有sku锁定库存成功
        if(lockedStockDTOs.size() == orderStockDTOS.size()){
            //将锁定库存的订单信息 缓存 等待关单/取消订单 释放库存
            redisTemplate.opsForValue().set("spzx:order:stock:"+orderStockDTOS.get(0).getOrderNo(),
                    orderStockDTOS);
        }
        //3、返回校验并设置了锁定状态的 库存对象集合
        return orderStockDTOS;
    }
    //释放订单库存


    @Transactional(rollbackFor = Exception.class)
    public void releaseLockStock(List<OrderStockDTO> lockedStockDTOs) {
        lockedStockDTOs.forEach(lockedStockDTO ->{
            baseMapper.releaseLockStock(lockedStockDTO);
        });

    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateStockAndSales(List<OrderStockDTO> orderStockDTOS) {
        //加销量 扣除库存
        // sale_num+skuNum , lock_num-skuNum
        orderStockDTOS.forEach(orderStockDTO -> {
            //对每个正在检查锁定库存的请求进行加锁
            baseMapper.updateStockAndSales(orderStockDTO);
        });

    }

    private void checkLockStock(List<OrderStockDTO> orderStockDTOS) {
        orderStockDTOS.forEach(orderStockDTO -> {
            //对每个正在检查锁定库存的请求进行加锁
            boolean flag = baseMapper.checkLockStock(orderStockDTO);
            orderStockDTO.setFlag(flag);
        });
    }
}
